package top.zhangjianyong.blog.service.impl;

import static top.zhangjianyong.blog.enums.RespCode.*;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.zhangjianyong.blog.entity.dto.RoleMenusDTO;
import top.zhangjianyong.blog.entity.po.Role;
import top.zhangjianyong.blog.entity.po.RoleMenu;
import top.zhangjianyong.blog.mapper.RoleMapper;
import top.zhangjianyong.blog.params.role.*;
import top.zhangjianyong.blog.record.DelAndAdd;
import top.zhangjianyong.blog.response.ApiResponse;
import top.zhangjianyong.blog.service.RoleMenuService;
import top.zhangjianyong.blog.service.RoleService;
import top.zhangjianyong.blog.service.UserRoleService;
import top.zhangjianyong.blog.utils.EntityUtil;

/**
 * 角色Service
 *
 * @author HDN
 * @since 2024/7/22 上午12:15
 */
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

  private final RoleMenuService roleMenuService;
  private final UserRoleService userRoleService;

  public RoleServiceImpl(RoleMenuService roleMenuService, UserRoleService userRoleService) {
    this.roleMenuService = roleMenuService;
    this.userRoleService = userRoleService;
  }

  @Override
  public ApiResponse page(RolePageParam param) {
    String roleName = param.roleName();
    Page<Role> page =
        lambdaQuery()
            .like(StrUtil.isNotBlank(roleName), Role::getRoleName, roleName)
            .page(new Page<>(param.pageNum(), param.pageSize()));
    return ApiResponse.success(page);
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public ApiResponse remove(RoleRemoveParam param) {
    boolean remove = removeById(param.id());
    if (!remove) return ApiResponse.fail(ROLE_DELETE_ERROR);
    userRoleService.removeByRole(param.id());
    roleMenuService.removeByRole(param.id());
    return ApiResponse.success();
  }

  @Override
  public ApiResponse saveOrUpdate(RoleSaveOrUpdateParam param) {
    Role role = new Role();
    BeanUtils.copyProperties(param, role);
    boolean result = null == role.getId() ? save(role) : updateById(role);
    return result ? ApiResponse.success() : ApiResponse.fail(ROLE_SAVE_OR_UPDATE_ROLE_ERROR);
  }

  @Override
  public ApiResponse menus(RoleMenusParam param) {
    return ApiResponse.success(getMenusByRoleId(param.id()));
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public ApiResponse menusUpdate(RoleMenusUpdateParam param) {
    // 查询所有菜单
    RoleMenusDTO roleMenusDTO = getMenusByRoleId(param.id());
    // 删除和新增菜单
    DelAndAdd<Long> delAndAdd = EntityUtil.getDelAndAdd(roleMenusDTO.getMenus(), param.menus());

    // 删除和新增操作
    boolean removeFlag = roleMenuService.remove(param.id(), delAndAdd.del());
    boolean saveFlag = roleMenuService.save(param.id(), delAndAdd.add());
    return removeFlag & saveFlag ? ApiResponse.success() : ApiResponse.fail(ROLE_MENU_UPDATE_ERROR);
  }

  @Override
  public ApiResponse list(RoleListParam param) {
    return ApiResponse.success(lambdaQuery().list());
  }

  private RoleMenusDTO getMenusByRoleId(Long id) {
    MPJLambdaWrapper<Role> wrapper =
        new MPJLambdaWrapper<Role>()
            .select(Role::getId)
            .selectCollection(
                RoleMenu.class, RoleMenusDTO::getMenus, map -> map.result(RoleMenu::getMenuId))
            .leftJoin(RoleMenu.class, RoleMenu::getRoleId, Role::getId)
            .eq(Role::getId, id);
    return baseMapper.selectJoinOne(RoleMenusDTO.class, wrapper);
  }
}
